package com.dycong.common.common;

import com.dycong.common.common.interAnno.ICustomConvert;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.ClassUtils;
import org.dom4j.*;

import java.util.*;

/**
 * Created by Kenti on 2017/1/9.
 */
@Log4j2
public class XstreamUtil {
    public static <T> T convertToObject(Class<T> clazz, String xml) {
        XStream xStream = new XStream();
        xStream.setMode(XStream.NO_REFERENCES);
        xStream.processAnnotations(clazz);
        xStream.ignoreUnknownElements();
        T xx = (T) xStream.fromXML(xml);
        if (ClassUtils.getAllInterfaces(clazz).contains(ICustomConvert.class)) {
            try {
                Document doc = DocumentHelper.parseText(xml);
                Element rootElement = doc.getRootElement();
                Map<String, String> map = new HashMap();
                xStream.alias("map",Map.class);
                ele2map(map,rootElement);

                ICustomConvert customConvert=(ICustomConvert)xx;
                customConvert.process(map);

                log.info(map);
            } catch (Exception e) {
                log.error("发生错误", e);
            }
        }
        return xx;
    }

    public static String convertToXml(Object o) {
        XStream xStream = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
        xStream.processAnnotations(o.getClass());
        xStream.setMode(XStream.NO_REFERENCES);
        XStreamAlias alias = o.getClass().getAnnotation(XStreamAlias.class);
        if (alias == null) {
            xStream.alias("xml", o.getClass());
        }
        return xStream.toXML(o);
    }

    /***
     * 核心方法，里面有递归调用
     *
     * @param map
     * @param ele
     */
    static void ele2map(Map map, Element ele) {
        // 获得当前节点的子节点
        List<Element> elements = ele.elements();
        if (elements.size() == 0) {
            // 没有子节点说明当前节点是叶子节点，直接取值即可
            map.put(ele.getName(), ele.getText());
        } else if (elements.size() == 1) {
            // 只有一个子节点说明不用考虑list的情况，直接继续递归即可
            Map<String, Object> tempMap = new HashMap<String, Object>();
            ele2map(tempMap, elements.get(0));
            map.put(ele.getName(), tempMap);
        } else {
            // 多个子节点的话就得考虑list的情况了，比如多个子节点有节点名称相同的
            // 构造一个map用来去重
            Map<String, Object> tempMap = new HashMap<String, Object>();
            for (Element element : elements) {
                tempMap.put(element.getName(), null);
            }
            Set<String> keySet = tempMap.keySet();
            for (String string : keySet) {
                Namespace namespace = elements.get(0).getNamespace();
                List<Element> elements2 = ele.elements(new QName(string, namespace));
                // 如果同名的数目大于1则表示要构建list
                if (elements2.size() > 1) {
                    List<Map> list = new ArrayList<Map>();
                    for (Element element : elements2) {
                        Map<String, Object> tempMap1 = new HashMap<String, Object>();
                        ele2map(tempMap1, element);
                        list.add(tempMap1);
                    }
                    map.put(string, list);
                } else {
                    // 同名的数量不大于1则直接递归去
                    Map<String, Object> tempMap1 = new HashMap<String, Object>();
                    ele2map(map, elements2.get(0));
                }
            }
        }
    }


    /**
     * 用法
     * @Log4j2
     @Data
     @XStreamAlias("xml")
     public class QueryRefundResult extends BusinessResult implements ICustomConvert{

    @XStreamAlias("out_trade_no")
    private String orderId;


    @XStreamAlias("transaction_id")
    private String transactionId;


    @XStreamAlias("fee_type")
    private String currencyType;

    @XStreamAlias("total_fee")
    private Integer totalAmount;


    @XStreamAlias("cash_fee")
    private Integer cashAmount;


    @XStreamAlias("refund_count")
    private Integer refundNumber;


    private List<SingleRefundResult> refundResultList;

    @Getter
    Map<String, String> xmlContent;

    @Override //todo 处理方法
    public void process(Map<String, String> xmlContent) {
        List<SingleRefundResult> refundResultList = new ArrayList<SingleRefundResult>();
        this.xmlContent=xmlContent;
        //解析动态属性
        for(int i=0;i<getRefundNumber();i++){
            SingleRefundResult sr = new SingleRefundResult();
            sr.setOutRefundId(xmlContent.get("out_refund_no_"+i));
            sr.setRefundId(xmlContent.get("refund_id_"+i));
            sr.setRefundChannel(xmlContent.get("refund_channel_"+i));
            sr.setRefundAmount(Integer.parseInt(xmlContent.get( "refund_fee_"+i)));
            sr.setRefundAccount(xmlContent.get("refund_recv_accout_"+i));
            sr.setRefundStatus(xmlContent.get("refund_status_"+i));
            refundResultList.add(sr);
        }

        setRefundResultList(refundResultList);

    }

     //todo 使用时->
     QueryRefundResult form= XstreamUtil.convertToObject(QueryRefundResult.class,result);
     */
}
